/* eslint-disable */
import Vue from 'vue'
import { saveWidget, updateWidget, queryFormulaList } from '@/api/widget'
import { cloneDeep } from 'lodash'
import {
  Module,
  VuexModule,
  getModule,
  Mutation,
  Action,
} from 'vuex-module-decorators'
import store from '@/store'
import { queryVisualizationData } from '@/api/visualization'

import {
  minBackgroundBoardWidth,
  minBackgroundBoardHeight,
  maxBackgroundBoardWidth,
  maxBackgroundBoardHeight,
} from '@/components/visualization/util'

import {
  GridItemDataInterface,
  KeyValueStore,
} from '@/components/vueGridLayout/interfate/grid-Item-data-inteface'
import {
  bindChartData,
  buildSaveParameters,
  parseGraphEdgeWeight,
} from '@/util/common'
import { VisSpec } from '@/util/recommend-visualization'
import KV from '@/components/form/kv'
import { parseChartOptionToFunction } from '@/components/common/VisualizationDashboard/util'

const isShowRulerLineCache =
  window.localStorage.getItem('isShowRulerLine') === '1' ? true : false

interface IOffset {
  x: number
  y: number
}

export interface IGridItemType {
  w: number
  h: number
  x: number
  y: number
  i: string
  type?: string
  id?: string
}

interface IDatasetPipelineDataList {
  dataset: Array<{
    id: number
    name: string
    tableName: string
  }>
  pipeline: Array<{
    id: number
    name: string
    tableName: string
  }>
}

export interface ICoordination {
  id: string
  sourceChartId: string
  context: string
}

export interface IChartLayout {
  gridW: number
  gridH: number
  gridX: number
  gridY: number
  width?: number
  height?: number
  left?: number
  top?: number
}

export interface IChartInfo {
  id: string
  type: string
  data?: any
  props?: Object
  layout: IChartLayout
  relation?: ICoordination[]
}

@Module({ dynamic: true, namespaced: true, name: 'VisualizationStore', store })
class VisualizationStore extends VuexModule {
  public isLoading: boolean = false
  public visualizationInstance: any
  public test: number = 10
  public scaleValue: number = 100 // 缩放比例，百分制
  public activeSettingItem: 'background' | 'chart' | 'text' = 'background' // canvas:画布设置 chart:图表设置
  public currentGridItem: GridItemDataInterface | null = null
  public gridList: Array<GridItemDataInterface> = []
  public chartList: IGridItemType[] = []
  public gridRowHeight = 10
  public gridColNum = 36
  public defaultGridWidth = 30
  public defaultGridHeight = 8
  public chartHeight = 190
  public girdMargin = [10, 10]
  public isRecommandPanelOpen: boolean = true
  public settingPanelIsOpen = false
  public SettingMode = 'property'
  public VisualizationContent: any = null
  public isFullMode: boolean = false
  public currentFilterFormAsCharts: Array<string | number> = []
  public datasetPipelineDataList: IDatasetPipelineDataList = {
    dataset: [],
    pipeline: [],
  } // 导入和pipeline的数据集
  public eventBus = new Vue()

  /** 右侧设置栏change事件屏蔽，用于filterForm在设计模式下执行getData操作 */
  public isSettingPanelChangeLock: boolean = false

  /**
   * dragStart时鼠标距离顶点相对距离
   */
  public draggingOffset: IOffset = {
    x: 0,
    y: 0,
  }

  public coordinations: ICoordination[] = []
  public components = []
  public chartInstanceMaps: KeyValueStore = {}

  public layoutData = {
    // 可视化画布属性
    width: 1180, // 宽度
    height: 1600, // 高度
    background: '#FFF', //背景色
  }

  public visualizationChartList: IChartInfo[] = []

  public visualizationMode: string = 'edit' // edit- 编辑态，preview - 预览态, publish - 发布态

  public selectedChartInfo: any = []

  public previewPopDisplay: string = '' //  close / open status

  public pipelineWidgetList: any = [] // pipeline下收藏的图表信息

  public currentDashboard: any = {}

  public recommendBaseSpec: VisSpec | null = null

  public shouldRecommendVisualization: boolean = true

  public tableColumnCache: KV = {}

  public isShowRulerLine: boolean = isShowRulerLineCache

  public get sortedChartList(): IGridItemType[] {
    const list = this.visualizationChartList.map((item) => ({
      i: item.id,
      x: item.layout.gridX,
      y: item.layout.gridY,
      w: item.layout.gridW,
      h: item.layout.gridH,
    }))
    return list.sort((a: IGridItemType, b: IGridItemType) => {
      if (a.y > b.y || (a.y === b.y && a.x > b.x)) {
        return 1
      }
      return -1
    })
  }

  public interactList: any = [] //  联动列表 [{child:..., parent: [...]}]
  public connectedList: any = [] //  [13345, ...]
  //  可视化系统 - 公式模块
  public formulaList: any = [] //  公式列表
  public insertFormula: any = {} // 被插入的公式参数
  public deleteFormula: any = {} //  被删除的公式参数
  public updateFormula: any = {} //  需要被更新的公式参数
  public highlightFormula: number = 0 // 需要高亮的公式id
  public editFormula: any = {} //  编辑的公式

  /** 当前项目下所有的dataset，用于filter-form初始化时查询 */
  public dataset: any[] = []
  public pipelineId: string | number = ''

  @Mutation
  setDataset(dataset: any[]) {
    this.dataset = dataset
  }

  @Mutation
  setPipelineId(id: string | number) {
    this.pipelineId = id
  }

  @Mutation
  setIsFullMode(status: boolean) {
    this.isFullMode = !!status
  }

  @Mutation
  setIsShowRulerLine(status: boolean) {
    this.isShowRulerLine = status
    window.localStorage.setItem('isShowRulerLine', status ? '1' : '0')
  }

  @Mutation
  public setVisualizationContent(vueInstance: any) {
    this.VisualizationContent = vueInstance
  }

  @Mutation
  public setTableColumnCache(data: {
    dataId: string
    fields: Array<any>
    columnBind: Array<any>
  }) {
    this.tableColumnCache[`dataId${data.dataId}`] = {
      fields: data.fields,
      columnBind: data.columnBind,
    }
  }

  @Mutation
  public setIsRecommandPanelOpen(isOpen: boolean) {
    this.isRecommandPanelOpen = isOpen
  }

  @Mutation
  public setDraggingOffset(data: IOffset) {
    this.draggingOffset = data
  }

  @Mutation
  public setLoadingStatus(isLoading: boolean) {
    this.isLoading = isLoading
  }

  @Mutation
  public setSettingMode(data: string) {
    this.SettingMode = data
  }
  @Mutation
  public setSettingPanelIsOpen(data: boolean) {
    this.settingPanelIsOpen = data
  }

  @Mutation
  public setChartInstanceMaps(data: { instance: any; key: string | number }) {
    this.chartInstanceMaps[data.key] = data.instance
  }

  @Mutation
  public clearChartInstanceMaps(key: string) {
    this.chartInstanceMaps[key] = undefined
  }

  @Mutation
  public clearAllChartInstanceMaps() {
    this.chartInstanceMaps = {}
  }

  @Mutation
  public setVisualizationInstance(chart: any): void {
    this.visualizationInstance = chart
  }

  @Mutation
  public setCurrentFilterFormAsCharts(chartIds: Array<string | number>) {
    this.currentFilterFormAsCharts = chartIds
  }

  /**
   * 更改缩放比例，百分制
   * @param value 新的缩放值
   */
  @Mutation
  public setScaleValue(value: number): void {
    this.scaleValue = value
  }

  /**
   * 切换当前的设置对象
   * @param active 当前设置对象
   */
  @Mutation
  public setActiveSettingItem(active: 'background' | 'chart' | 'text'): void {
    this.activeSettingItem = active
    this.settingPanelIsOpen = true
  }

  /**
   * 设置当前需要配置的chart
   * @param data
   */
  @Mutation
  public setCurrentGridItem(data: GridItemDataInterface | null): void {
    const tag = data && this.currentGridItem?.i === data?.i

    this.currentGridItem = data
    if (!tag) {
      this.recommendBaseSpec = null
    }
  }

  @Mutation
  public setGridList(data: Array<GridItemDataInterface>) {
    this.gridList = data
  }

  /**
   * 添加布局数据
   * @param data
   */
  @Mutation
  public addGridItem(data: GridItemDataInterface) {
    this.gridList.push(data)
  }

  /**
   * 删除布局数据
   * @param data
   */
  @Mutation
  public removeGridItem(index: number, length: number = 1) {
    this.gridList.splice(index, length)
  }

  /**
   * 设置gridItem
   * @param data
   * @param index
   */
  @Mutation
  public setGridItem(data: { gridItem: GridItemDataInterface; index: number }) {
    this.gridList.splice(data.index, 1, cloneDeep(data.gridItem))
    // this.gridList[index] = cloneDeep(data)
  }
  savingMaps: KeyValueStore = {}
  /**
   * 为gridItem 绑定数据
   * @param query 查询参数
   * @param data 数据
   */
  @Mutation
  public gridItemBindData(
    data: KeyValueStore,
    gridItemSet?: GridItemDataInterface,
    keepCurrentGridItem?: boolean
  ) {
    const gridItem = bindChartData(gridItemSet || this.currentGridItem, data)
    if (gridItem && gridItem.chartOptions) {
      const dom = (document as any).body.querySelector(
        `#grid-item-${gridItem.i}`
      )
      if (dom) {
        Vue.set(gridItem.chartOptions, 'size', [
          dom.offsetWidth,
          dom.offsetHeight,
        ])
      }
      Vue.set(gridItem, 'chartType', cloneDeep(gridItem.chartType))
    }

    this.gridList.forEach((dataItem: GridItemDataInterface, index: number) => {
      if (gridItem && dataItem.i === gridItem.i) {
        const parameters = buildSaveParameters(gridItem)
        if (!gridItem.widgetId && this.savingMaps[gridItem.i]) {
          return
        }
        if (this.currentDashboard.id) {
          parameters.data.dashboardId = this.currentDashboard.id
        }
        const apiFetch = gridItem.widgetId ? updateWidget : saveWidget
        this.savingMaps[gridItem.i] = true
        apiFetch(parameters)
          .then((response) => {
            this.savingMaps[gridItem.i] = false
            if (response.data.code === 100 && !gridItem.widgetId) {
              gridItem.widgetId = response.data.result
            }
            Vue.set(this.gridList, index, gridItem)
            parseChartOptionToFunction(gridItem.chartOptions)
            // 某些情况下无需设置当前gridItem，例如filterForm任务触发
            if (!keepCurrentGridItem) {
              this.currentGridItem = gridItem
            }
          })
          .catch(() => {
            this.savingMaps[gridItem.i] = false
            if (this.visualizationInstance) {
              this.visualizationInstance.$message.error('widget信息同步失败')
            }
          })
      }
    })
  }

  @Mutation
  public gridItemBindGraphData({
    data = {},
    formData = {},
    targetGridItem,
  }: {
    data: KeyValueStore
    formData: KeyValueStore
    targetGridItem: GridItemDataInterface
  }) {
    const gridItem = targetGridItem || this.currentGridItem
    if (!gridItem) {
      return
    }
    const targetGridIndex = this.gridList.findIndex(
      (dataItem: GridItemDataInterface) => {
        return gridItem && dataItem.i === gridItem.i
      }
    )
    if (
      targetGridIndex === -1 ||
      (!gridItem.widgetId && this.savingMaps[gridItem.i])
    ) {
      return
    }

    gridItem.chartOptions.value = data
    gridItem.chartOptions = {
      ...gridItem.chartOptions,
      ...formData,
    }
    parseGraphEdgeWeight(gridItem)
    gridItem.showChart = true
    const parameters = buildSaveParameters(gridItem)
    if (this.currentDashboard.id) {
      parameters.data.dashboardId = this.currentDashboard.id
    }
    delete parameters.data.tid // graph 数据集没有对应的id，统一删除掉
    const apiFetch = gridItem.widgetId ? updateWidget : saveWidget
    this.savingMaps[gridItem.i] = true
    apiFetch(parameters)
      .then((response) => {
        this.savingMaps[gridItem.i] = false
        if (response.data.code === 100 && !gridItem.widgetId) {
          gridItem.widgetId = response.data.result
        }
        Vue.set(this.gridList, targetGridIndex, gridItem)
        this.currentGridItem = gridItem
      })
      .catch(() => {
        this.savingMaps[gridItem.i] = false
        if (this.visualizationInstance) {
          this.visualizationInstance.$message.error('widget信息同步失败')
        }
      })
  }

  /**
   * 更新widget
   * @param gridItem
   */
  @Mutation
  public updateWidget(parameterSet: {
    gridItem: any
    index: number
    onSuccess?: Function
    onError?: Function
    syncUpdate?: boolean
    onlyLocal?: boolean
  }) {
    const { gridItem, index, onSuccess, onError } = parameterSet
    /** 只在画布上保存无需走一遍接口 */
    if (parameterSet.onlyLocal) {
      this.gridList[parameterSet.index].i === gridItem.i &&
        Vue.set(this.gridList, index, gridItem)
      return
    }
    const parameters = buildSaveParameters(gridItem)
    const apiFetch = gridItem.widgetId ? updateWidget : saveWidget
    gridItem.isLoading = true
    apiFetch(parameters)
      .then((response) => {
        gridItem.isLoading = false
        if (response.data.code === 100 && !gridItem.widgetId) {
          gridItem.widgetId = response.data.result
        }
        const indexSet = this.gridList.findIndex((dataItem) => {
          return dataItem.i === gridItem.i
        })
        if (indexSet >= 0) {
          Vue.set(this.gridList, index, gridItem)
          if (
            this.currentGridItem?.i === gridItem.i &&
            parameterSet.syncUpdate
          ) {
            this.currentGridItem = gridItem
          }
          console.log('updateWidget after gridItem:', gridItem)
        }
        /** 加载成功回调 */
        onSuccess && onSuccess(gridItem)
        onError && onError(gridItem)
        if (parameterSet.syncUpdate) {
          Vue.set(this.gridList, index, gridItem)
        }
        // Vue.set(this.gridList, index, gridItem)
      })
      .catch(() => {
        gridItem.isLoading = false
        if (this.visualizationInstance) {
          this.visualizationInstance.$message.error('widget信息同步失败')
        }
      })
  }

  @Mutation
  public gridItemSyncBindData(parameterSet: any) {
    const { data, gridItem, index, withFilter, noChangeCurrent } = parameterSet
    const gridItemSet: GridItemDataInterface | null = bindChartData(
      gridItem,
      data
    )
    if (gridItemSet) {
      if (gridItemSet.chartOptions) {
        const dom = (document as any).body.querySelector(
          `#grid-item-${gridItemSet.i}`
        )
        if (dom) {
          gridItemSet.chartOptions.size = [dom.offsetWidth, dom.offsetHeight]
        }
      }
      Vue.nextTick(() => {
        Vue.set(this.gridList, index, gridItemSet)
        // 因为每次绑定会深拷贝所以需要在这里重新设置一遍当前激活widget
        if (!(noChangeCurrent || withFilter)) {
          this.currentGridItem = gridItemSet
        }
      })
    }
  }
  /**
   * 更改画布宽度
   * @param width 画布宽度
   */
  @Mutation
  public setBackgroundWidth(width: number): void {
    this.layoutData.width = width
    if (width < minBackgroundBoardWidth) {
      this.layoutData.width = minBackgroundBoardWidth
    } else if (maxBackgroundBoardWidth < width) {
      this.layoutData.width = maxBackgroundBoardWidth
    }

    this.gridColNum = Math.floor(this.layoutData.width / 8)
    this.defaultGridWidth = 30
  }

  /**
   * 更改画布高度
   * @param height 画布高度
   */
  @Mutation
  public setBackgroundHeight(height: number): void {
    this.layoutData.height = height
    if (height < minBackgroundBoardHeight) {
      this.layoutData.height = minBackgroundBoardHeight
    } else if (maxBackgroundBoardHeight < height) {
      this.layoutData.height = maxBackgroundBoardHeight
    }
  }

  /**
   * 设置背景色
   * @param color
   */
  @Mutation
  public setBackgroundColor(color: string): void {
    this.layoutData.background = color
  }

  /**
   * 添加图表
   * @param value 添加的图表项
   */
  @Mutation
  public pushChartList(newChart: IChartInfo): void {
    this.visualizationChartList.push(newChart)
  }

  /**
   * 添加交互语句
   * @param context 交互语句
   */
  @Mutation
  public addCoordination(context: string) {
    // eslint-disable-next-line unicorn/prefer-set-has
    const coorIds = this.coordinations.map((item: ICoordination) => item.id)
    let newId = ''
    /* eslint-disable */
    do {
      newId = '00000000'
        .concat(
          // eslint-disable-next-line radix
          Number.parseInt(`${Math.random() * 4294967296}`)
            .toString(16)
            .toUpperCase()
        )
        .slice(-8)
    } while (coorIds.includes(newId))
    const newCoor = {
      id: newId,
      sourceChartId: this.currentGridItem?.i as string,
      context,
    }
    this.coordinations.push(newCoor)
  }

  /**
   * 删除交互语句
   * @param id 交互语句id
   */
  @Mutation
  public deleteCoordination(id: string) {
    this.coordinations = this.coordinations.filter(
      (item: ICoordination) => item.id !== id
    )
  }

  /**
   * 更新交互语句
   * @param param0
   */
  @Mutation
  public updateCoordination({ id, context }: ICoordination) {
    this.coordinations.forEach((element: ICoordination, index: number) => {
      if (element.id === id) {
        this.coordinations[index].context = context
      }
    })
  }

  @Mutation
  public setCoordination(list: ICoordination[]) {
    this.coordinations = list
  }

  @Mutation
  public updateGridLayout(newLayout: any) {
    console.log(this.visualizationChartList, newLayout)
  }

  @Mutation
  public updateVisualizationData(data: any) {
    const { layout, chartList } = data
    this.layoutData = layout
    this.visualizationChartList = chartList
  }

  @Mutation
  public changeVisualizationMode(mode: string) {
    this.visualizationMode = mode
  }

  @Mutation
  public setInteractList(list: any[]) {
    this.interactList = list
  }

  @Mutation
  public setConnectedList(list: any[]) {
    this.connectedList = list
  }

  @Mutation
  public addSelectedChartInfo(info: any) {
    //  select / unselect
    const list = [info.widgetId]
    const result = this.selectedChartInfo.filter(
      (item: any) => !list.includes(item.widgetId)
    )

    if (result.length === this.selectedChartInfo.length) {
      this.selectedChartInfo.push(info)
    } else {
      result.push(info)
      this.selectedChartInfo = result
    }
  }

  @Mutation
  public removeSelectedChartInfo(index: number) {
    this.selectedChartInfo.splice(index, 1)
  }

  @Mutation
  public setSelectedChartInfo(info: any) {
    this.selectedChartInfo = info
  }

  @Mutation
  public changePreviewPopStatus(status: string) {
    this.previewPopDisplay = status
  }

  /**
   * 可视化系统 - 公式模块
   */
  public get getInsertFormula() {
    return this.insertFormula
  }

  public get getDeleteFormula() {
    return this.deleteFormula
  }

  public get getUpdateFormula() {
    return this.updateFormula
  }

  public get getFormulaList() {
    return this.formulaList
  }

  public get getEditFormula() {
    return this.editFormula
  }

  @Mutation
  public updateInsertFormula(item: any) {
    this.insertFormula = item
  }

  @Mutation
  public setDeleteFormula(item: any) {
    this.deleteFormula = item
  }

  @Mutation
  public setUpdateFormula(item: any) {
    this.updateFormula = item
  }

  public get getHighlightFormula() {
    return this.highlightFormula
  }

  @Mutation
  public setHighlightFormula(id: number) {
    this.highlightFormula = id
  }

  @Mutation
  public updateFormulaList(list: any) {
    this.formulaList = list
  }

  @Mutation
  public updateEditFormula(item: any) {
    this.editFormula = item
  }

  @Action({ commit: 'updateFormulaList' })
  public async fetchFormulaList(target: any = {}) {
    const response: any =
      target.pipelineId === undefined
        ? await queryFormulaList({
            data: {
              projectId: target.projectId,
            },
          })
        : await queryFormulaList({
            data: {
              ...target,
            },
          })

    if (response.data.code === 100) {
      return response.data.result.datasetList
    }
    return []
  }

  /**
   * pipeline下收藏的图表
   */
  @Mutation
  public updatePipelineWidgetList(list: any) {
    this.pipelineWidgetList = list
  }

  @Mutation
  public setCurrentDashboardData(data: any) {
    this.currentDashboard = data
  }

  @Action({ commit: 'updateVisualizationData' })
  public async getVisualizationData(projectId: string) {
    const response = await queryVisualizationData({ id: projectId })

    return response.data.result
  }

  @Mutation
  public toggleShouldRecommendVisualization() {
    this.shouldRecommendVisualization = !this.shouldRecommendVisualization
  }

  @Mutation
  public setRecommendBaseSpec(spec: VisSpec | null) {
    this.recommendBaseSpec = spec
  }

  @Action
  public async recommendVisualization(spec?: VisSpec) {
    if (!this.shouldRecommendVisualization) return // TODO 放这儿不合适吧
    if (!spec && !this.currentGridItem) return
    if (!spec) return
    this.setRecommendBaseSpec(spec)
  }

  @Mutation
  public setDatasetPipelineDataList(list: IDatasetPipelineDataList) {
    this.datasetPipelineDataList = list
  }

  /** 设置右侧banner change事件触发状态锁定 */
  @Mutation
  public setIsSettingPanelChangeLock(status: boolean) {
    this.isSettingPanelChangeLock = status
  }
}

export default getModule(VisualizationStore)
